package com.tools.middle.elasticsearch;

import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch.core.search.HighlightField;
import com.tools.common.container.OwnPairs;
import com.tools.common.object.Note;
import com.tools.common.thread.Timeunit;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 在一个字段中精确匹配多个内容
 * 继承父类的方法在多条件查询时不起作用
 * */
@Note("在一个字段中精确匹配多个内容。" +
        "继承父类的方法在多条件查询时不起作用")
public final class TermsSearch extends Search {

    @Note("字段名称")
    private String field;

    @Note("要精确匹配的多个内容")
    private List<FieldValue> values;

    /* **********************************************************************************
     *
     *          构造器
     *
     * *********************************************************************************
     * */

    public TermsSearch(String field, String value) {
        this.setField(field);
        this.setValues(value);
    }

    public TermsSearch(String field, String... values) {
        this.setField(field);
        this.setValues(values);
    }

    public TermsSearch(String field, Iterable<String> values) {
        this.setField(field);
        this.setValues(values);
    }

    public static TermsSearch of(String field, String value) {
        return new TermsSearch(field, value);
    }

    public static TermsSearch of(String field, String... values) {
        return new TermsSearch(field, values);
    }

    public static TermsSearch of(String field, Iterable<String> values) {
        return new TermsSearch(field, values);
    }

    /* **********************************************************************************
     *
     *          Getter / Setter
     *
     * *********************************************************************************
     * */

    public String getField() {
        return field;
    }

    public void setField(String field) {
        default_fieldNotEmpty(field);
        this.field = field;
    }

    public List<FieldValue> getNewValues() {
        return (values == null || values.isEmpty())
                ? new ArrayList<>()
                : new ArrayList<>(values);
    }

    public List<FieldValue> getValues() {
        return values;
    }

    public void setValues(String value) {
        private_valueNotEmpty(value);
        this.values = new ArrayList<>(1);
        this.values.add(FieldValue.of(value));
    }

    public void setValues(String... values) {
        int length = default_getArrayLength(values);
        if(length == 0) return;
        this.values = new ArrayList<>(length);
        for (String v : values) {
            private_valueNotEmpty(v);
            this.values.add(FieldValue.of(v));
        }
    }

    public void setValues(Iterable<String> values) {
        int size = default_getIterableSize(values);
        if(size == 0) return;
        this.values = new ArrayList<>(size);
        for (String v : values) {
            private_valueNotEmpty(v);
            this.values.add(FieldValue.of(v));
        }
    }

    /* **********************************************************************************
     *
     *          链式调用
     *
     * *********************************************************************************
     * */

    public TermsSearch field(String field) {
        this.setField(field);
        return this;
    }

    public TermsSearch values(String value) {
        this.setValues(value);
        return this;
    }

    public TermsSearch values(String... values) {
        this.setValues(values);
        return this;
    }

    public TermsSearch values(Iterable<String> values) {
        this.setValues(values);
        return this;
    }

    @Override
    public TermsSearch indicesNames(String indicesName) {
        super.indicesNames(indicesName);
        return this;
    }

    @Override
    public TermsSearch indicesNames(String... indicesNames) {
        super.indicesNames(indicesNames);
        return this;
    }

    @Override
    public TermsSearch indicesNames(Iterable<String> indicesNames) {
        super.indicesNames(indicesNames);
        return this;
    }

    @Override
    public TermsSearch timeout(String timeout) {
        super.timeout(timeout);
        return this;
    }

    @Override
    public TermsSearch timeout(int timeout, Timeunit timeunit) {
        super.timeout(timeout, timeunit);
        return this;
    }

    @Override
    public TermsSearch from(int from) {
        super.from(from);
        return this;
    }

    @Override
    public TermsSearch size(int size) {
        super.size(size);
        return this;
    }

    @Override
    public TermsSearch analyzer(String analyzer) {
        super.analyzer(analyzer);
        return this;
    }

    @Override
    public TermsSearch sorts(String field, SortOrder order) {
        super.sorts(field, order);
        return this;
    }

    @Override
    public TermsSearch sorts(Map<String, SortOrder> fieldAndOrders) {
        super.sorts(fieldAndOrders);
        return this;
    }

    @Override
    public TermsSearch sorts(OwnPairs<String, SortOrder> fieldAndOrders) {
        super.sorts(fieldAndOrders);
        return this;
    }

    @Override
    public TermsSearch includes(String includeField) {
        super.includes(includeField);
        return this;
    }

    @Override
    public TermsSearch includes(String... includeFields) {
        super.includes(includeFields);
        return this;
    }

    @Override
    public TermsSearch includes(Iterable<String> includeFields) {
        super.includes(includeFields);
        return this;
    }

    @Override
    public TermsSearch excludes(String excludeField) {
        super.excludes(excludeField);
        return this;
    }

    @Override
    public TermsSearch excludes(String... excludeFields) {
        super.excludes(excludeFields);
        return this;
    }

    @Override
    public TermsSearch excludes(Iterable<String> excludeFields) {
        super.excludes(excludeFields);
        return this;
    }

    @Override
    public TermsSearch aggregations(String field, Aggregation agg) {
        super.aggregations(field, agg);
        return this;
    }

    @Override
    public TermsSearch aggregations(Map<String, Aggregation> aggregations) {
        super.aggregations(aggregations);
        return this;
    }

    @Override
    public TermsSearch aggregations(OwnPairs<String, Aggregation> aggregations) {
        super.aggregations(aggregations);
        return this;
    }

    @Override
    public TermsSearch highlights(String field, HighlightField highlight) {
        super.highlights(field, highlight);
        return this;
    }

    @Override
    public TermsSearch highlights(Map<String, HighlightField> highlights) {
        super.highlights(highlights);
        return this;
    }

    @Override
    public TermsSearch highlights(OwnPairs<String, HighlightField> highlights) {
        super.highlights(highlights);
        return this;
    }

    /* **********************************************************************************
     *
     *          自定义方法
     *
     * *********************************************************************************
     * */

    public TermsSearch addValue(String value) {
        private_valueNotEmpty(value);
        private_initValueList(1);
        this.values.add(FieldValue.of(value));
        return this;
    }

    public TermsSearch addValues(String... values) {
        int length = default_getArrayLength(values);
        if(length == 0) return this;
        private_initValueList(length);
        for (String v : values) {
            private_valueNotEmpty(v);
            this.values.add(FieldValue.of(v));
        }
        return this;
    }

    public TermsSearch addValues(Iterable<String> values) {
        int size = default_getIterableSize(values);
        if(size == 0) return this;
        private_initValueList(size);
        for (String v : values) {
            private_valueNotEmpty(v);
            this.values.add(FieldValue.of(v));
        }
        return this;
    }

    public TermsSearch modifyValue(int index, String newValue) {
        if(values != null && !values.isEmpty() && !default_indexCheck(index, values.size())) {
            private_valueNotEmpty(newValue);
            this.values.set(index, FieldValue.of(newValue));
        }
        return this;
    }

    public TermsSearch clearValues() {
        if(values != null && !values.isEmpty()) this.values.clear();
        return this;
    }

    public TermsSearch removeValue(int index) {
        if(values != null && !values.isEmpty() && !default_indexCheck(index, values.size())) {
            this.values.remove(index);
        }
        return this;
    }

    public TermsSearch removeValue(String value) {
        if(value == null || value.isEmpty()) return this;
        if(values != null && !values.isEmpty()) {
            values.removeIf(fv -> value.equals(private_getValue(fv)));
        }
        return this;
    }

    public TermsSearch removeValues(String... values) {
        if(values == null || values.length == 0) return this;
        if(this.values != null && !this.values.isEmpty()) {
            for (String v : values) this.values.remove(v);
        }
        return this;
    }

    public TermsSearch removeValues(Iterable<String> values) {
        if(values == null) return this;
        if(this.values != null && !this.values.isEmpty()) {
            for (String v : values) this.values.remove(v);
        }
        return this;
    }

    public String getValue(int index) {
        if(values != null && !values.isEmpty() && !default_indexCheck(index, values.size())) {
            return private_getValue(values.get(index));
        }
        return null;
    }

    public int valueSize() {
        return (values == null) ? 0 : values.size();
    }

    public boolean containsValue(String value) {
        return values != null && !values.isEmpty() && values.contains(value);
    }


    @Override
    public TermsSearch addIndicesName(String indicesName) {
        super.addIndicesName(indicesName);
        return this;
    }

    @Override
    public TermsSearch addIndicesNames(String... indicesNames) {
        super.addIndicesNames(indicesNames);
        return this;
    }

    @Override
    public TermsSearch addIndicesNames(Iterable<String> indicesNames) {
        super.addIndicesNames(indicesNames);
        return this;
    }

    @Override
    public TermsSearch modifyIndicesName(int index, String indicesName) {
        super.modifyIndicesName(index, indicesName);
        return this;
    }

    @Override
    public TermsSearch removeIndicesName(String indicesName) {
        super.removeIndicesName(indicesName);
        return this;
    }

    @Override
    public TermsSearch removeIndicesName(int index) {
        super.removeIndicesName(index);
        return this;
    }

    @Override
    public TermsSearch removeIndicesNames(String... indicesNames) {
        super.removeIndicesNames(indicesNames);
        return this;
    }

    @Override
    public TermsSearch removeIndicesNames(Iterable<String> indicesNames) {
        super.removeIndicesNames(indicesNames);
        return this;
    }

    @Override
    public TermsSearch addSort(String field, SortOrder order) {
        super.addSort(field, order);
        return this;
    }

    @Override
    public TermsSearch addSorts(Map<String, SortOrder> fieldAndOrders) {
        super.addSorts(fieldAndOrders);
        return this;
    }

    @Override
    public TermsSearch addSorts(OwnPairs<String, SortOrder> fieldAndOrders) {
        super.addSorts(fieldAndOrders);
        return this;
    }

    @Override
    public TermsSearch modifySort(int index, String field, SortOrder order) {
        super.modifySort(index, field, order);
        return this;
    }

    @Override
    public TermsSearch clearSorts() {
        super.clearSorts();
        return this;
    }

    @Override
    public TermsSearch removeSort(String field, SortOrder order) {
        super.removeSort(field, order);
        return this;
    }

    @Override
    public TermsSearch removeSort(int index) {
        super.removeSort(index);
        return this;
    }

    @Override
    public TermsSearch removeSorts(Map<String, SortOrder> fieldAndOrders) {
        super.removeSorts(fieldAndOrders);
        return this;
    }

    @Override
    public TermsSearch removeSorts(OwnPairs<String, SortOrder> fieldAndOrders) {
        super.removeSorts(fieldAndOrders);
        return this;
    }

    @Override
    public TermsSearch addInclude(String field) {
        super.addInclude(field);
        return this;
    }

    @Override
    public TermsSearch addIncludes(String... fields) {
        super.addIncludes(fields);
        return this;
    }

    @Override
    public TermsSearch addIncludes(Iterable<String> fields) {
        super.addIncludes(fields);
        return this;
    }

    @Override
    public TermsSearch modifyInclude(int index, String field) {
        super.modifyInclude(index, field);
        return this;
    }

    @Override
    public TermsSearch clearIncludes() {
        super.clearIncludes();
        return this;
    }

    @Override
    public TermsSearch removeInclude(String field) {
        super.removeInclude(field);
        return this;
    }

    @Override
    public TermsSearch removeInclude(int index) {
        super.removeInclude(index);
        return this;
    }

    @Override
    public TermsSearch removeIncludes(String... fields) {
        super.removeIncludes(fields);
        return this;
    }

    @Override
    public TermsSearch removeIncludes(Iterable<String> fields) {
        super.removeIncludes(fields);
        return this;
    }

    @Override
    public TermsSearch addExclude(String field) {
        super.addExclude(field);
        return this;
    }

    @Override
    public TermsSearch addExcludes(String... fields) {
        super.addExcludes(fields);
        return this;
    }

    @Override
    public TermsSearch addExcludes(Iterable<String> fields) {
        super.addExcludes(fields);
        return this;
    }

    @Override
    public TermsSearch modifyExclude(int index, String field) {
        super.modifyExclude(index, field);
        return this;
    }

    @Override
    public TermsSearch clearExcludes() {
        super.clearExcludes();
        return this;
    }

    @Override
    public TermsSearch removeExclude(String field) {
        super.removeExclude(field);
        return this;
    }

    @Override
    public TermsSearch removeExclude(int index) {
        super.removeExclude(index);
        return this;
    }

    @Override
    public TermsSearch removeExcludes(String... fields) {
        super.removeExcludes(fields);
        return this;
    }

    @Override
    public TermsSearch removeExcludes(Iterable<String> fields) {
        super.removeExcludes(fields);
        return this;
    }

    @Override
    public TermsSearch addAgg(String field, Aggregation agg) {
        super.addAgg(field, agg);
        return this;
    }

    @Override
    public TermsSearch addAggs(Map<String, Aggregation> aggs) {
        super.addAggs(aggs);
        return this;
    }

    @Override
    public TermsSearch addAggs(OwnPairs<String, Aggregation> aggs) {
        super.addAggs(aggs);
        return this;
    }

    @Override
    public TermsSearch clearAggs() {
        super.clearAggs();
        return this;
    }

    @Override
    public TermsSearch removeAgg(String field) {
        super.removeAgg(field);
        return this;
    }

    @Override
    public TermsSearch removeAgg(String... fields) {
        super.removeAgg(fields);
        return this;
    }

    @Override
    public TermsSearch removeAgg(Iterable<String> fields) {
        super.removeAgg(fields);
        return this;
    }

    @Override
    public TermsSearch addHighlight(String field, HighlightField highlight) {
        super.addHighlight(field, highlight);
        return this;
    }

    @Override
    public TermsSearch addHighlights(Map<String, HighlightField> highlights) {
        super.addHighlights(highlights);
        return this;
    }

    @Override
    public TermsSearch addHighlights(OwnPairs<String, HighlightField> highlights) {
        super.addHighlights(highlights);
        return this;
    }

    @Override
    public TermsSearch clearHighlight() {
        super.clearHighlight();
        return this;
    }

    @Override
    public TermsSearch removeHighlight(String field) {
        super.removeHighlight(field);
        return this;
    }

    @Override
    public TermsSearch removeHighlights(String... fields) {
        super.removeHighlights(fields);
        return this;
    }

    @Override
    public TermsSearch removeHighlights(Iterable<String> fields) {
        super.removeHighlights(fields);
        return this;
    }

    /* **********************************************************************************
     *
     *          私有逻辑
     *
     * *********************************************************************************
     * */

    @Note("要搜索的内容的非空校验")
    private static void private_valueNotEmpty(String value) {
        if(value == null || value.isEmpty()) throw new NullPointerException("要精确搜索的内容不能为空");
    }

    @Note("初始化要精确搜索的内容的列表")
    private void private_initValueList(int initSize) {
        if(values == null) this.values = new ArrayList<>(initSize);
    }

    @Note("将值转为字符串输出")
    private String private_getValue(FieldValue fv) {
        Object o = fv._get();
        return (o == null) ? null : o.toString();
    }
}
